home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 42
/
Amiga Format AFCD42 (Issue 126, Aug 1999).iso
/
-serious-
/
comms
/
other
/
slrn
/
slrn_src
/
src
/
sltcp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-05-14
|
15KB
|
766 lines
/* -*- mode: C; mode: fold; -*- */
/* Copyright (c) 1998 John E. Davis (davis@space.mit.edu)
*
* This file is part of slrn.
*
* Slrn is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* Slrn is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with Slrn; see the file COPYING. If not, write to the Free
* Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
/*{{{ Include Files */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>
#include <stdarg.h>
#include <setjmp.h>
#include <signal.h>
#include <sys/types.h>
#ifdef HAVE_SOCKET_H
# include <socket.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h>
#endif
#if defined(__NT__)
# include <winsock.h>
# define USE_WINSOCK_SLTCP 1
#else
# if defined(__MINGW32__)
# define Win32_Winsock
# include <windows.h>
# define USE_WINSOCK_SLTCP 1
# endif
#endif
#ifdef USE_WINSOCK_SLTCP
# define USE_WINSOCK_SLTCP 1
#else
# include <netdb.h>
#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
#ifdef HAVE_ARPA_INET_H
# include <arpa/inet.h>
#endif
#ifndef h_errno
extern int h_errno;
#endif
/* For select system call */
#ifdef VMS
# include <unixio.h>
# include <socket.h>
# include <in.h>
# include <inet.h>
#else
# if !defined(USE_WINSOCK_SLTCP)
# include <sys/time.h>
# endif
# if defined(__QNX__) || defined(__os2__)
# include <sys/select.h>
# endif
# if defined (_AIX) && !defined (FD_SET)
# include <sys/select.h> /* for FD_ISSET, FD_SET, FD_ZERO */
# endif
# ifndef FD_SET
# define FD_SET(fd, tthis) *(tthis) = 1 << (fd)
# define FD_ZERO(tthis) *(tthis) = 0
# define FD_ISSET(fd, tthis) (*(tthis) & (1 << fd))
typedef int fd_set;
# endif
#endif
#include <slang.h>
#include "sltcp.h"
/*}}}*/
#if defined(__BEOS__) || defined(USE_WINSOCK_SLTCP)
# define SLTCP_CLOSE(x) closesocket(x)
# define SLTCP_READ(x,y,z) recv((x),(y),(z),0)
# define SLTCP_WRITE(x,y,z) send((x),(y),(z),0)
#else
# define SLTCP_CLOSE(x) close(x)
# define SLTCP_READ(x,y,z) read((x),(y),(z))
# define SLTCP_WRITE(x,y,z) write((x),(y),(z))
#endif
int (*SLTCP_Interrupt_Hook) (void);
int SLtcp_TimeOut_Secs = 120;
static int TCP_Verbose_Reporting = 0;
static int sys_call_interrupted_hook (void) /*{{{*/
{
if (SLTCP_Interrupt_Hook == NULL)
return 0;
return (*SLTCP_Interrupt_Hook) ();
}
/*}}}*/
/* This function attempts to make a connection to a specified port on an
* internet host. It returns a socket descriptor upon success or -1
* upon failure.
*/
static int get_tcp_socket_1 (char *host, int port) /*{{{*/
{
char **h_addr_list;
/* h_addr_list is NULL terminated if h_addr is defined. If h_addr
* is not defined, h_addr is the only element in the list. When
* h_addr is defined, its value is h_addr_list[0].
*/
int h_length;
int h_addr_type;
char *fake_h_addr_list[2];
unsigned long fake_addr;
struct sockaddr_in s_in;
int s;
int not_connected;
/* If it does not look like a numerical address, use nameserver */
if (!isdigit(*host) || (-1L == (long)(fake_addr = inet_addr (host))))
{
struct hostent *hp;
unsigned int max_retries = 3;
while (NULL == (hp = gethostbyname (host)))
{
#ifdef TRY_AGAIN
max_retries--;
if (max_retries && (h_errno == TRY_AGAIN))
{
sleep (1);
continue;
}
#endif
fprintf(stderr, "%s: Unknown host.\n", host);
return -1;
}
#ifdef h_addr
h_addr_list = hp->h_addr_list;
#else
h_addr_list = fake_h_addr_list;
h_addr_list [0] = hp->h_addr;
h_addr_list [1] = NULL;
#endif
h_length = hp->h_length;
h_addr_type = hp->h_addrtype;
}
else
{
h_addr_list = fake_h_addr_list;
h_addr_list [0] = (char *) &fake_addr;
h_addr_list [1] = NULL;
h_length = sizeof(struct in_addr);
h_addr_type = AF_INET;
}
memset ((char *) &s_in, 0, sizeof(s_in));
s_in.sin_family = h_addr_type;
s_in.sin_port = htons((unsigned short) port);
if (-1 == (s = socket (h_addr_type, SOCK_STREAM, 0)))
{
perror("socket");
return -1;
}
not_connected = -1;
while (not_connected
&& (h_addr_list != NULL)
&& (*h_addr_list != NULL))
{
char *this_host;
memcpy ((char *) &s_in.sin_addr, *h_addr_list, h_length);
this_host = (char *) inet_ntoa (s_in.sin_addr);
if (TCP_Verbose_Reporting) fprintf (stderr, "trying %s\n", this_host);
not_connected = connect (s, (struct sockaddr *)&s_in, sizeof (s_in));
if (not_connected == -1)
{
#ifdef EINTR
if (errno == EINTR) /* If interrupted, try again. */
{
if (0 == sys_call_interrupted_hook ())
continue;
}
#endif
fprintf (stderr, "connection to %s, port %d:",
(char *) this_host, port);
perror ("");
}
h_addr_list++;
}
if (not_connected)
{
fprintf(stderr, "Unable to make connection. Giving up.\n");
(void) SLTCP_CLOSE (s);
return -1;
}
return s;
}
/*}}}*/
#if HAVE_SIGLONGJMP
/*{{{ get_tcp_socket routines with sigsetjmp/siglongjmp */
static void restore_sigint_handler (void (*f)(int), int call_it) /*{{{*/
{
if (f == SIG_ERR)
return;
(void) SLsignal_intr (SIGINT, f);
if (call_it)
kill (getpid (), SIGINT);
}
/*}}}*/
static sigjmp_buf Sigint_Jmp_Buf;
static void (*Old_Sigint_Handler) (int);
static volatile int Jump_In_Progress;
static void sigint_handler (int sig) /*{{{*/
{
(void) sig;
if (Jump_In_Progress) return;
Jump_In_Progress = 1;
siglongjmp (Sigint_Jmp_Buf, 1);
}
/*}}}*/
static int get_tcp_socket (char *host, int port) /*{{{*/
{
int fd;
Old_Sigint_Handler = SIG_ERR;
Jump_In_Progress = 1; /* dont allow jump yet */
if (0 != sigsetjmp (Sigint_Jmp_Buf, 1)) /* save signal mask */
{
restore_sigint_handler (Old_Sigint_Handler, 1);
sys_call_interrupted_hook ();
return -1;
}
Old_Sigint_Handler = SLsignal_intr (SIGINT, sigint_handler);
if ((Old_Sigint_Handler == SIG_IGN)
|| (Old_Sigint_Handler == SIG_DFL))
{
restore_sigint_handler (Old_Sigint_Handler, 0);
Old_Sigint_Handler = SIG_ERR;
}
Jump_In_Progress = 0; /* now allow the jump */
fd = get_tcp_socket_1 (host, port);
Jump_In_Progress = 1; /* don't allow jump */
restore_sigint_handler (Old_Sigint_Handler, 0);
return fd;
}
/*}}}*/
/*}}}*/
#else
static int get_tcp_socket (char *host, int port) /*{{{*/
{
return get_tcp_socket_1 (host, port);
}
/*}}}*/
#endif /* HAVE_SIGLONGJMP */
SLTCP_Type *sltcp_open_connection (char *host, int port) /*{{{*/
{
int fd;
SLTCP_Type *tcp;
tcp = (SLTCP_Type *) SLMALLOC (sizeof (SLTCP_Type));
if (tcp == NULL)
{
fprintf (stderr, "Memory Allocation Failure.\n");
return NULL;
}
memset ((char *) tcp, 0, sizeof (SLTCP_Type));
tcp->tcp_fd = -1;
tcp->tcp_read_ptr = tcp->tcp_read_ptr_max = tcp->tcp_read_buf;
tcp->tcp_write_ptr = tcp->tcp_write_ptr_min = tcp->tcp_write_buf;
fd = get_tcp_socket (host, port);
if (fd == -1)
{
SLFREE (tcp);
return NULL;
}
tcp->tcp_fd = fd;
return tcp;
}
/*}}}*/
static unsigned int do_write (SLTCP_Type *tcp, unsigned char *buf, unsigned int len) /*{{{*/
{
unsigned int total;
int nwrite;
int fd;
total = 0;
fd = tcp->tcp_fd;
while (total != len)
{
nwrite = SLTCP_WRITE (fd, (char *) buf, (len - total));
if (nwrite == -1)
{
#ifdef EAGAIN
if (errno == EAGAIN)
{
sleep (1);
continue;
}
#endif
#ifdef EWOULDBLOCK
if (errno == EWOULDBLOCK)
{
sleep (1);
continue;
}
#endif
#ifdef EINTR
if (errno == EINTR)